using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NLite.Collections;
using NLite.Mini.Context;
using NLite.Reflection;
using NLite.Internal;

namespace NLite.Mini.Activation
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class DefaultActivator : AbstractActivator
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected override object InternalCreate(IPreCreationContext context)
        {
            return CreateInstance(context);
        }

        internal object CreateInstance(IPreCreationContext context)
        {
            ConstructorInfo constructorInfo = null;
            var impType = context.Component.Implementation;

            if (impType.IsAbstract || impType.IsInterface)
                throw new ActivatorException(
                   string.Format(
                       "Type {0} is abstract.\r\n As such, it is not possible to instansiate it as implementation of {1} service",
                       impType.FullName,
                       context.Component.Contracts[0].FullName));

            if (impType.IsOpenGenericType())
                impType = impType.MakeCloseGenericType(context.GenericParameters);

            if (context.NamedArgs != null && context.NamedArgs.Count > 0)
                constructorInfo = impType.FindEligibleConstructor(context.NamedArgs);
            else if (context.Args != null && context.Args.Length > 0)
                constructorInfo = impType.FindEligibleConstructor(context.Args);
            else
                constructorInfo = ReflectionHelper.FindEligibleConstructor(impType,context.Kernel);

            if (constructorInfo == null)
            {
                if (impType.IsValueType)
                {
                    return Activator.CreateInstance(impType);
                }
            }

            object[] parms = null;

            if (context.NamedArgs != null && context.NamedArgs.Count > 0)
                parms = context.NamedArgs.Values.ToArray();
            else if (context.Args != null && context.Args.Length > 0)
                parms = context.Args;
            else
                parms = ReflectionHelper.GetParameters(impType, constructorInfo, context.Kernel);

            return constructorInfo.FastInvoke(parms);
        }

       
    }
}
